/*
cli_cmd.c
offer uart debug port function realizy,app debug entry
designed by lunanting
----------------------
2020-03-20 17:13:30
creat file
---------------------

*/

#include "cli_cmd.h"
#include "stdio.h"
#include "string.h"
#include "stdarg.h"
#include "aos/kernel.h"
#include "xp_time.h"
#include "aos/vfs.h"
#include "sys/fcntl.h"
#include "rtc_time.h"

#define LOG_recode
// #define filename(x) strrchr(x,'/')?strrchr(x,'/')+1:x

static aos_sem_t cli_sem,print_sem, upLoad_sem;
//char type[21],fun[21],param[21];
static char type[51]={0},fun[51]={0},param[80]={0};
static int (*cli_debug[100])(char*,char*,char*);
static int debug_foot=0;
static char cli_pj[20]={0};
static char cli_ver[20]={0};
static int log_switch=0;    //日志记录动态开关

int app_debug(char *type,char *fun,char *param);
void xp_cmd_debug(char *buf,int len,int argc,char **argv);
int xp_io_debug(char *type,char *fun,char *param);  //io debug
static int xp_cli_debug_run(char *type,char *fun,char *param);
void xp_print_buf_set(char *str);
static void xp_print_thread(void *arg);
void (*tcp_log_print)(void *,char *)=NULL;
static void *log_server=NULL;
#ifdef LOG_recode
void xp_log_push(char *str);
#endif

//cli cmd array
static struct cli_command xp_cmd[]={
    {"xp","xp app debug",xp_cmd_debug},
};

/*
x project cmd debug entry
param:
    argc:cmd param num
    argv:cmd param array
*/
void xp_cmd_debug(char *buf,int len,int argc,char **argv){
    if(argc>1){
        strncpy(type,argv[1],50);
    }
    if(argc>2){
        strncpy(fun,argv[2],50);
    }
    if(argc>3){
        strncpy(param,argv[3],80);
    }
    //strncpy(param,argv[3],20);
    aos_sem_signal(&cli_sem);
}

/*
set debug cmd
param:
    type: type
    fun: fun
    param: param
*/
void xp_cli_cmd_set(char *ty,char *fu,char *pa){
    strncpy(type,ty,50);
    strncpy(fun,fu,50);
    strncpy(param,pa,80);
    aos_sem_signal(&cli_sem);
}

/*
debug port thread
*/
void xp_cli_thread(void *arg){
    char t[51],f[51],p[80];
    aos_task_t id;

    // aos_task_new_ext(&id,"println",xp_print_thread,NULL,2500,30);
    while(1){
        aos_sem_wait(&cli_sem,AOS_WAIT_FOREVER);
        aos_msleep(5);
        memcpy(t,type,50);
        memcpy(f,fun,50);
        memcpy(p,param,80);
        memset(type,0,50);
        memset(fun,0,50);
        memset(param,0,80);
        if(strcmp(t,"test")==0){
            println("\r\n   Hello,user\r\n    Here is the 1kmxc application system platform\r\n    Designed by lunanting\r\n");
        }
        else if(strcmp(t,"restart")==0){
            println("system will restart....\r\n");
            aos_reboot();
        }
        else if(strcmp(t,"version")==0){
            println("project: %s. version: %s.\r\n",cli_pj,cli_ver);
        }
        #ifdef LOG_recode
        else if(strcmp(t,"log_close")==0){
            void xp_log_close(void);
            xp_log_close();
        }
        else if(strcmp(t,"time")==0){
            println("RTC time: %s. systime: %s.",xp_time_get_string(),xp_msTostring(aos_now_ms()));
        }
        else if(strcmp(t,"log_list")==0){
            xp_logList_show();
        }
        else if(strcmp(t,"log_hold_check")==0){
            xp_logHold_check();
        }
        else if(strcmp(t,"log_switch")==0){
            xp_logSwitch_set(atoi(f));
        }
        #endif
        else if(xp_io_debug(t,f,p)){}
        else if(xp_cli_debug_run(t,f,p)){}
        else if(app_debug(t,f,p)){}
        else{
            println("command error!\r\n");
        }
    }
}

static char bufLogUpload[pSize+1]={0};
static aos_queue_t logUplaod_queue = {0};

/*
x project cli cmd debug function init

*/
void xp_cli_init(void){
    if(aos_cli_register_commands(&xp_cmd[0],1)==0){
        printf("Cli cmd debug access success !\r\n");
    }
    else{
        printf("Cli cmd debug access fail !\r\n");
    }
    aos_sem_new(&cli_sem,0);
    aos_sem_new(&print_sem,1);
    aos_sem_new(&upLoad_sem,1);
    debug_foot=0;
    aos_task_new("cli debug",xp_cli_thread,NULL,2500);
    #ifdef LOG_recode
    void xp_log_recode_tasK(void *arg);
    if(aos_task_new("log recode",xp_log_recode_tasK,NULL,2500)!=0)return;
    #endif
    void xp_log_upload_task(void *arg);
    aos_task_new("log_upload",xp_log_upload_task,NULL, 4096);
    void *pMem = aos_malloc(sizeof(bufLogUpload)*10);
    aos_queue_new(&logUplaod_queue, pMem, sizeof(bufLogUpload)*10, sizeof(bufLogUpload));
}

static char buf1[pSize+1]={0},buf2[pSize+1]={0};

/*
print string with enter
param:
    print string
*/
void printo(const char *str,...){
    if(aos_sem_wait(&print_sem,100)!=0){
        return;
    }
    va_list va;
    va_start(va,str);
    vsnprintf(buf1,pSize-30,str,va);
    va_end(va);
    snprintf(buf2,pSize,"[%s] %s",xp_timeMS_string_get(),buf1);
    #ifdef LOG_recode
    xp_log_push(buf2);
    #endif
    printf("%s",buf2);
    // xp_print_buf_set(buf2);
    aos_sem_signal(&print_sem);
}

/*
print string 
*/
void print(const char *str,...){
    if(aos_sem_wait(&print_sem,100)!=0){
        return;
    }
    va_list va;
    va_start(va,str);
    vsnprintf(buf1,pSize,str,va);
    va_end(va);
    // snprintf(buf2,pSize,"[%s] %s",xp_timeMS_string_get(),buf1);
    printf("%s",buf1);
    aos_sem_signal(&print_sem);
}

/*
debug print singal thread
*/
#include "stdlib.h"
#include "k_api.h"
#define PRINT_SEND_BUF_SIXE 30
static char (*s_buf)[pSize+1]=NULL;
static int s_foot=0,g_foot=0;
static aos_sem_t send_sem;
static aos_mutex_t send_mux;


/*
set print data
param:
    str: print string
*/
void xp_print_buf_set(char *str){
    u32 count=10;
    if(s_buf==NULL)return;
    aos_mutex_lock(&send_mux,100);
    krhino_sem_count_get(send_sem.hdl,&count);
    if(count>=PRINT_SEND_BUF_SIXE){
        aos_mutex_unlock(&send_mux);
        return;
    }
    memset(s_buf+s_foot,0,pSize);
    strncpy(s_buf+s_foot,str,pSize);
    s_foot++;
    if(s_foot>=PRINT_SEND_BUF_SIXE){
        s_foot=0;
    }
    aos_sem_signal(&send_sem);
    aos_mutex_unlock(&send_mux);
}

/*
get print data pointer
return:
    NULL= no data
*/
char *xp_print_buf_get(void){
    u32 count=0;
    char *p;

    if(s_buf==NULL)return NULL;
    aos_mutex_lock(&send_mux,100);
    p=s_buf+g_foot;
    g_foot++;
    if(g_foot>=PRINT_SEND_BUF_SIXE){
        g_foot=0;
    }
    aos_mutex_unlock(&send_mux);
    return p;
}

static void xp_print_thread(void *arg){
    char *buf=NULL;
    s_foot=0;
    g_foot=0;
    aos_sem_new(&send_sem,0);
    aos_mutex_new(&send_mux);
    s_buf=(char *)malloc((pSize+1)*PRINT_SEND_BUF_SIXE);
    memset(s_buf,0,(pSize+1)*PRINT_SEND_BUF_SIXE);

    while(1){
        aos_sem_wait(&send_sem,AOS_WAIT_FOREVER);
        buf=xp_print_buf_get();
        if(buf!=NULL){
            printf(buf);
            if(tcp_log_print!=NULL){
                tcp_log_print(log_server,buf);
            }
        }
    }
}


/*
printf buffer
param:
    data:buffer
    len:data length
    data_w:data type
    type:print type,10=10进制打印，16=16进制打印
*/
void print_buf(const void *data,const u8 len,const u8 data_w,const u8 type){
    int var=0;
    u8 foot=0; 
    
    if(data==NULL)return;
    foot=data_w/8;
    for(u8 i=0;i<len;i++){
        memcpy(&var,data+i*foot,foot);
        if(type==10){
            print("%d ",var);
        }
        else if(type==16){
            print("%X ",var);
        }
    }
    print("\r\n");
}


/*
add debug api
param:
    api:ebug api
return:
    0=success
*/
int xp_cli_debug_add(int (*api)(char *,char *,char *)){
    if(debug_foot<100){
        cli_debug[debug_foot++]=api;
    }
    else{
        perr("debug api too much~");
        return -1;
    }
    return 0;
}

/*
cli debug run
*/
static int xp_cli_debug_run(char *type,char *fun,char *param){
    for(int i=0;i<debug_foot;i++){
        if(cli_debug[i](type,fun,param)){
            return 1;
        }
    }
    return 0;
}


/*
cli debug println channel
param:
    channel: debug log channel
    str:debug format string
*/
void println_debug(int channel,const char *str,...){
    
}


/*
regist tcp print api
param:
    print_api: tcp print api
*/
void xp_cli_tcp_print_regist(void (*print_api)(void *,char *),void *server){
    tcp_log_print=print_api;
    log_server=server;
    println("regist tcp print api !");
}

/*************************log upload************************/
static int (*xp_mqtt_send_log)(char *arg);
static bool isLogUpload = true;
static aos_sem_t sem_logUpload;

/**
 * @brief       日志上报回调
 * @param[in]	callback            
 */
void xp_mqtt_send_log_callback_regist(int (*callback)(char *arg))
{
    xp_mqtt_send_log = callback;
}

/**
 * @brief       设置日志上报标志
 * @param[in]	enable              
 */
void set_log_upload_flag(bool enable)
{
    isLogUpload = enable;
}
void print_up_log(const char *str,...){
    if(aos_sem_wait(&upLoad_sem,100)!=0){
        return;
    }
    va_list va;
    va_start(va,str);
    vsnprintf(bufLogUpload,pSize,str,va);
    va_end(va);
    if(isLogUpload && xp_mqtt_send_log != NULL){
        aos_queue_send(&logUplaod_queue, bufLogUpload, sizeof(bufLogUpload));
    }
    aos_sem_signal(&upLoad_sem);
}

void xp_log_upload_task(void *arg)
{
    uint32_t len = 0;
    char buf[pSize] = {0};

    aos_msleep(2000);
    while(1){
        aos_queue_recv(&logUplaod_queue, AOS_WAIT_FOREVER, buf, &len);
        xp_mqtt_send_log(buf);
    }
}

/*************************log recode************************/
#ifdef LOG_recode
static char log_buf[5][pSize]={0};
static aos_sem_t sem_log;
static int fl=NULL;
static u8 foot_set,foot_get;
static int f_count;
static char fn[50]={0};
static u64 time_last;
static int log_exit=1;
/*
init log module
return:
    0=success
*/
int xp_log_init(void){

    memset(log_buf,0,sizeof(log_buf));
    foot_set=0;
    foot_get=0;
    if(aos_sem_new(&sem_log,0)!=0)return -1;
    aos_dir_t *dp=(aos_dir_t*)aos_opendir("/sdcard/log");
    if(dp==NULL){
        if(aos_mkdir("/sdcard/log")!=0){
            printf("\r\nNO SD CARD\r\n\r\n");
            // log_exit=1;
            return -4;
        }
    }
    else{
        aos_closedir(dp);
    }
    if(log_switch==1){
        snprintf(fn,49,"/sdcard/log/%s.txt",xp_date_hour_string_get());
        printf("open file: %s\r\n",fn);
        // fl=open(fn,"w");
        fl=aos_open(fn,O_RDWR|O_CREAT|O_APPEND);
        if(fl==NULL){
            printf("log recode init fail~\r\n");
            return -3;
        }
    }
    log_exit=0;
    printf("log recode init success !!\r\n");
    return 0;
}


/*
log file write task
*/
void xp_log_recode_tasK(void *arg){
    char buf[200]={0};
    char path[50];

    aos_msleep(2000);
    xp_log_init();
    // if(log_exit==1){
    //     aos_task_exit(-1);
    // }
    memset(buf,0,200);
    while(1){
        aos_sem_wait(&sem_log,AOS_WAIT_FOREVER);
        if(log_switch==0){
            if(fl!=NULL){
                aos_sync(fl);
                aos_close(fl);
                fl=NULL;
                strcpy(fn,"no");
            }
            continue;
        }
        strncpy(buf,log_buf[foot_get++],pSize-1);
        snprintf(path,49,"/sdcard/log/%s.txt",xp_date_hour_string_get());
        if(strcmp(fn,path)!=0){
            if(fl!=NULL){
                aos_sync(fl);
                aos_close(fl);
            }
            xp_logHold_check();
            strncpy(fn,path,49);
            fl=aos_open(fn,O_RDWR|O_CREAT|O_APPEND);
            if(fl==NULL){
                continue;
                // log_exit=1;
                // aos_task_exit(-1);
            }
            time_last=aos_now_ms();
            print("open log file: %s.",path);
        }
        if(aos_write(fl,buf,strlen(buf))<0){
            printf("write file fail~\r\n");
            if(fl!=NULL){
                aos_sync(fl);
                aos_close(fl);
            }
            continue;
            // log_exit=1;
            // aos_task_exit(-1);
        }
        if(foot_get==5){
            foot_get=0;
            if(fl!=NULL){
                aos_sync(fl);
            }
        }
    }
}


/*
set log recode switch
param:
    switch: 0=close , 1=open
*/
void xp_logSwitch_set(int sta){
    if(sta==0){
        log_switch=0;
    }
    else{
        log_switch=1;
    }
    println("Log switch set as: %d.",sta);
}



/*
log recode push
param:
    str:recode string
*/
void xp_log_push(char *str){
    if(log_exit==1)return;
    snprintf(log_buf[foot_set],pSize-1,"%s",str);
    foot_set++;
    if(foot_set==5)foot_set=0;
    aos_sem_signal(&sem_log);
}


/*
close fl
*/
void xp_log_close(void){
    aos_close(fl);
}


#endif

static int log_holdDays=7;
static char *fp="/sdcard/log";
/*
recode log file auto remove
default hold 7 days
*/
void xp_logHold_check(void){
    aos_dirent_t *dirent;
    int fd;
    aos_dir_t *dp;
    int datef[4]={0};
    time_t tt1=0,tt2=0;
    struct tm tp={0};
    char buf[50]={0};

    tt1=xp_time_get_unix();
    dp=aos_opendir(fp);
    if(fp==NULL)return;
    while(1){
        dirent=aos_readdir(dp);
        if(dirent==NULL)
            break;
        sscanf(dirent->d_name,"%d-%d-%d-%d.txt",&datef[0],&datef[1],&datef[2],&datef[3]);
        tp.tm_year=datef[0]-1900;
        tp.tm_mon=datef[1]-1;
        tp.tm_mday=datef[2];
        tp.tm_hour=datef[3];
        tp.tm_isdst=-1;
        // print("ssanf %d, %d, %d, %d.\n",datef[0],datef[1],datef[2],datef[3]);
        tt2=mktime(&tp);
        if(abs(tt1-tt2)>(3600*24*log_holdDays)){
            // print("tt2: %lld, tt1: %lld.\n",tt2,tt1);
            snprintf(buf,49,"%s/%s",fp,dirent->d_name); 
            if(aos_unlink(buf)==0){
                print("Delete %s log file.\n",buf);
            }
            else{
                print("Delete %s log file fail. try remove as fold.\n",buf);
                snprintf(buf,49,"%s/%s/",fp,dirent->d_name); 
                if(aos_rmdir(buf)==0){
                    print("rmove as fold ok.\n");
                }
            }
        }
        krhino_task_yield();
    }
    aos_closedir(dp);
}


/*
set recode log hold days
*/
void xp_logHoldDays_set(int days){
    if(days<1){
        days=7;
    }
    log_holdDays=days;
}

/*
show log file list
*/
void xp_logList_show(void){
    aos_dirent_t *dirent;
    int fd;
    aos_dir_t *dp;
    int count=1;

    dp=aos_opendir(fp);
    if(fp==NULL)return;
    while(1){
        dirent=aos_readdir(dp);
        if(dirent==NULL)
            break;
        println("file%d:    %s    %d    %d.",count,dirent->d_name,dirent->d_type,dirent->d_ino);
        count++;
        krhino_task_yield();
    }
    aos_closedir(dp);
}



/*
wellcome worlds
param:
    app:application name
    version:framwork version
*/
void xp_wellcome_worlds(char *app,char *version){
    strncpy(cli_pj,app,19);
    strncpy(cli_ver,version,19);
    printf("                     wellcome to 1KM app system\n");
    printf("Designed by lunanting\n");
    printf("*****************************system message*************************\n");
    printf("project:%s\n",app);
    printf("version: %s\n",version);
    printf("------->driver init\n");
}


int __attribute__((weak)) app_debug(char *type,char *fun,char *param){
    // println("No define app debug enry!");
    return 0;
}
//end of the file
